﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace SimilarWordsWCFService
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
                     ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class SimilarWordsWCFService : ISimilarWordsWCFService
    {
        private static EnglishDictionary dictionary = new EnglishDictionary();

        private const int NUMBER_OF_WORDS_TO_RETURN = 10;
        /// <summary>
        /// Find words in the english dictionary that are similar to the
        /// word passed in. The passed in parameter does not need to be a 
        /// valid "word" it can be any string. Caches responses for 24 hours
        /// to prevent additional processing for duplicate word checks.
        /// </summary>
        /// <param name="str">Any string.</param>
        /// <returns>A list of words that are similar to the passed in string.</returns>
        public string[] SimilarWords(string str)
        {
            Dictionary<string, double> similarWordsAndWeights;
            if (CacheHelper.Exists(str))
            {
                CacheHelper.Get(str, out similarWordsAndWeights);
            }
            else
            {
                similarWordsAndWeights = new Dictionary<string, double>();
                foreach (DictionaryEntry dictionaryWord in dictionary.Words)
                {
                    double similarity = 0.0;
                    if ((similarity = dictionaryWord.similarTo(str)) != 0.0)
                    {
                        try
                        {
                            similarWordsAndWeights.Add(dictionaryWord.Word, similarity);
                        }
                        catch (Exception e)
                        {
                            //This is less expensive than checking contains each time.
                        }
                    }
                }
                CacheHelper.Add(similarWordsAndWeights, str);
            }
            return getTopWords(similarWordsAndWeights);
        }

        private string[] getTopWords<T, U>(Dictionary<T, U> similarWordsAndWeights) where U : IComparable
        {
            var myList = similarWordsAndWeights.ToList();

            myList.Sort((firstPair, nextPair) =>
            {
                return -firstPair.Value.CompareTo(nextPair.Value);
            }
            );
            var dictionary = myList.ToDictionary((keyItem) => keyItem.Key, (valueItem) => valueItem.Value);
            if (similarWordsAndWeights.Count < NUMBER_OF_WORDS_TO_RETURN)
            {
                return createStringArrayFromGenericList(dictionary.Keys.ToList().GetRange(0, similarWordsAndWeights.Count));
            }
            return createStringArrayFromGenericList(dictionary.Keys.ToList().GetRange(0, NUMBER_OF_WORDS_TO_RETURN));
        }

        private string[] createStringArrayFromGenericList<T>(List<T> list)
        {
            string[] output = new string[list.Count()];
            int i = 0;
            foreach (T item in list)
            {
                output[i] = item.ToString();
                i++;
            }
            return output;
        }
    }
}
